//+------------------------------------------------------------------+
//|                                                  Well Martin.mq5 |
//|                                              Copyright 2015, AM2 |
//|                                      http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, AM2"
#property link      "http://www.forexsystems.biz"
#property version   "1.00"
//---
#include <Trade\Trade.mqh>            // 包含交易函数库 CTrade
//--- 输入参数设置 Bollinger Bands
input int      BBPeriod  = 84;        // 布林带周期
input int      BBShift   = 0;         // 相对图表的位移
input double   BBDev     = 1.8;       // 标准方差
//--- 输入参数设置 ADX
input int      ADXPeriod = 40;        // ADX 周期
input int      ADXLevel  = 45;        // ADX 级别
//--- 输入参数设置
input int      TP        = 1200;      // 止盈
input int      SL        = 1400;      // 止损
input int      Slip      = 50;        // 滑点
input int      Stelth    = 0;         // 模式: 1-止损位只对用户可见
input double   KLot      = 2;         // 手数的倍数
input double   MaxLot    = 5;         // 最大手数
input double   Lot       = 0.1;       // 交易手数
input color    LableClr  = clrGreen;  // 标签颜色
//--- 全局变量
int BBHandle;                         // 指标句柄 Bolinger Bands
int ADXHandle;                        // 指标句柄 ADX
double BBUp[],BBLow[];                // 动态数组用于存储指标数据 Bollinger Bands
double ADX[];                         // 动态数组用于存储指标数据 ADX
CTrade trade;                         // 交易函数库 CTrade
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 创建 Bollinger Bands 和 ADX 指标
   BBHandle=iBands(_Symbol,0,BBPeriod,BBShift,BBDev,PRICE_CLOSE);
   ADXHandle=iADX(_Symbol,0,ADXPeriod);

//--- 检查指标句柄，如果无效则返回 INIT_FAILED
   if(BBHandle==INVALID_HANDLE || ADXHandle==INVALID_HANDLE)
     {
      Print(" failed to create Bollinger Bands or ADX indicator");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- 释放 Bollinger Bands 和 ADX 指标
   IndicatorRelease(BBHandle);
   IndicatorRelease(ADXHandle);
//--- 删除所有对象
   ObjectsDeleteAll(0,0,OBJ_ARROW_LEFT_PRICE);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- 获取最新价格数据
   MqlRates mrate[];
//--- 设置数组为序列模式
   ArraySetAsSeries(mrate,true);
//--- 设置 Bollinger Bands 和 ADX 指标数组为序列模式
   ArraySetAsSeries(BBUp,true);
   ArraySetAsSeries(BBLow,true);
   ArraySetAsSeries(ADX,true);
//--- 获取最新价格数据
   if(CopyRates(_Symbol,_Period,0,3,mrate)<0)
     {
      Alert("获取最新价格数据失败 - 错误代码:",GetLastError(),"!!");
      return;
     }
//--- 获取 Bollinger Bands 指标数据
   if(CopyBuffer(BBHandle,1,0,3,BBUp)<0 || CopyBuffer(BBHandle,2,0,3,BBLow)<0)
     {
      Alert("获取 Bollinger Bands 指标数据失败 - 错误代码:",GetLastError(),"!");
      return;
     }
//--- 获取 ADX 指标数据
   if(CopyBuffer(ADXHandle,0,0,3,ADX)<0)
     {
      Alert("获取 ADX 指标数据失败 - 错误代码:",GetLastError(),"!");
      return;
     }
//--- 获取最新价格
   double Ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double Bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
//---
   double pr=0;
   double stop=0,take=0;
//--- 创建布尔变量，用于判断是否满足交易条件 Bolinger Bands 和 ADX
//--- 买入条件 Bolinger Bands 和 ADX
   bool Buy=Ask<BBLow[1] && ADX[1]<ADXLevel && (LastDealType()==0 || LastDealType()==2);
//--- 卖出条件 Bolinger Bands 和 ADX
   bool Sell=Bid>BBUp[1] && ADX[1]<ADXLevel && (LastDealType()==0 || LastDealType()==1);
//--- 新柱线判断
   if(IsNewBar(_Symbol,0))
     {
      //--- 买入条件满足，且无持仓
      if(PositionsTotal()<1 && Buy)
        {
         //--- 设置止损止盈
         if(SL==0)stop=0; else stop=NormalizeDouble(Ask-SL*_Point,_Digits);
         if(TP==0)take=0; else take=NormalizeDouble(Ask+TP*_Point,_Digits);
         //--- 隐藏止损止盈
         if(Stelth==1) {stop=0;take=0;}
         //--- 开仓
         trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,Volume(),Ask,stop,take);
         //--- 设置标签
         if(Stelth==1) PutLable("SL"+DoubleToString(Ask,_Digits),TimeCurrent(),NormalizeDouble(Ask-SL*_Point,_Digits),LableClr);
         if(Stelth==1) PutLable("TP"+DoubleToString(Ask,_Digits),TimeCurrent(),NormalizeDouble(Ask+TP*_Point,_Digits),LableClr);
        }
      //--- 卖出条件满足，且无持仓
      if(PositionsTotal()<1 && Sell)
        {
         //--- 设置止损止盈
         if(SL==0)stop=0; else stop=NormalizeDouble(Bid+SL*_Point,_Digits);
         if(TP==0)take=0; else take=NormalizeDouble(Bid-TP*_Point,_Digits);
         //--- 隐藏止损止盈
         if(Stelth==1) {stop=0;take=0;}
         //--- 开仓
         trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,Volume(),Bid,stop,take);
         if(Stelth==1) PutLable("TP"+DoubleToString(Bid,_Digits),TimeCurrent(),NormalizeDouble(Bid-TP*_Point,_Digits),LableClr);
         if(Stelth==1) PutLable("SL"+DoubleToString(Bid,_Digits),TimeCurrent(),NormalizeDouble(Bid+SL*_Point,_Digits),LableClr);
        }
     }
//--- 持仓判断
//--- 持仓判断
   if(PositionSelect(_Symbol) && Stelth==1)
     {
      //--- 买入持仓
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
         //--- 持仓盈亏判断
         pr=(Bid-PositionGetDouble(POSITION_PRICE_OPEN))/_Point;
         if(pr>=TP)
           {
            //--- 平仓
            trade.PositionClose(_Symbol);
           }
         if(pr<=-SL)
           {
            //--- 平仓
            trade.PositionClose(_Symbol);
           }
        }
      //--- 卖出持仓
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
         //--- 持仓盈亏判断
         pr=(PositionGetDouble(POSITION_PRICE_OPEN)-Bid)/_Point;
         if(pr>=TP)
           {
            //--- 平仓
            trade.PositionClose(_Symbol);
           }
         if(pr<=-SL)
           {
            //--- 平仓
            trade.PositionClose(_Symbol);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| 设置标签函数                                                 |
//+------------------------------------------------------------------+
void PutLable(const string name="",datetime time=0,double price=0,const color clr=clrGreen)
  {
//--- 创建对象
   ResetLastError();
//--- 创建对象
   if(!ObjectCreate(0,name,OBJ_ARROW_LEFT_PRICE,0,time,price))
     {
      Print(__FUNCTION__,
            ": 创建对象失败! 错误代码 = ",GetLastError());
      return;
      //--- 设置对象属性
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      //--- 设置对象样式
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
      //--- 设置对象宽度
      ObjectSetInteger(0,name,OBJPROP_WIDTH,2);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsNewBar(string symbol,ENUM_TIMEFRAMES timeframe)
  {
//---- 获取最新价格时间
   datetime TNew=datetime(SeriesInfoInteger(symbol,timeframe,SERIES_LASTBAR_DATE));
   datetime m_TOld=0;
//--- 获取最新价格时间
   if(TNew!=m_TOld && TNew)
     {
      m_TOld=TNew;
      //--- 返回 true
      return(true);
      Print("新柱线!");
     }
//--- 旧柱线判断
   return(false);
  }
//+------------------------------------------------------------------+
//| 获取交易手数 根据交易历史记录                            |
//+------------------------------------------------------------------+
double Volume(void)
  {
   double lot=Lot;
//--- 获取历史数据
   HistorySelect(0,TimeCurrent());
//--- 获取历史订单
   int orders=HistoryDealsTotal();
//--- 获取历史交易
   ulong ticket=HistoryDealGetTicket(orders-1);
   if(ticket==0)
     {
      Print("历史数据获取失败! ");
      lot=Lot;
     }
//--- 获取历史交易利润
   double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
//--- 获取历史交易量
   double lastlot=HistoryDealGetDouble(ticket,DEAL_VOLUME);
//--- 利润判断
   if(profit<0.0)
     {
      //--- 亏损后增加倍数
      lot=lastlot*KLot;
      Print(" 亏损后增加倍数! ");
     }
//--- 获取最小交易量
   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;
//--- 最大手数判断
   if(lot>MaxLot)
      lot=Lot;
//--- 返回交易手数
   return(lot);
  }
//+------------------------------------------------------------------+
//| 获取最后交易类型 根据交易历史记录                            |
//+------------------------------------------------------------------+
int LastDealType(void)
  {
   int type=0;
//--- 获取历史数据
   HistorySelect(0,TimeCurrent());
//--- 获取历史订单
   int orders=HistoryDealsTotal();
//--- 获取历史交易
   ulong ticket=HistoryDealGetTicket(orders-1);
//--- 历史数据判断
   if(ticket==0)
     {
      Print("历史数据获取失败! ");
      type=0;
     }
   if(ticket>0)
     {
      //--- 判断 BUY 交易
      if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY)
        {
         type=2;
        }
      //--- 判断 SELL 交易
      if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL)
        {
         type=1;
        }
     }
//---
   return(type);
  }
//+------------------------------------------------------------------+
